﻿create procedure [mem].[kvSet]
(
	@Key varchar(255) not null,
	@TTL float not null,
	@Version int null,
	@Harden bit null = 1,
	@NewVersion int out,
	@Expiry datetime2 out,
	@Values mem.kvValues readonly
) 
with NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
as
begin atomic with (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')

	set @Expiry = DATEADD(millisecond, @TTL, GETUTCDATE())
	declare @KeyId bigint

	if @Version is null
		begin
			insert mem.kv
			(
				[Key],
				[Version],
				Expiry,
				Harden
			)
			values 
			(
				@Key,
				-2147483647,
				@Expiry,
				@Harden
			)

			set @NewVersion = -2147483647
			set @KeyId = scope_identity()
		end
	else
		begin
			declare @OldVersion int
			update mem.kv 
				set 
					@KeyId = [KeyId],
					@OldVersion = [Version],
					Expiry = @Expiry,
					[Version] = [Version] + 1
				where [Key] = @Key 

			if @@rowcount = 0
			begin
				-- This forces an upstream GET, otherwise this cannot be native compiled.
				set @NewVersion = -2147483648
				return;
			end

			if @Version != @OldVersion 
			begin
				declare @message nvarchar(350)
				set @message = 'Concurrency violation for key [' + @Key + ']. Reselect the value and try again.';
				throw 60001, @message, 1;
			end

			set @NewVersion = @OldVersion + 1
			delete mem.kvValues where [KeyId] = @KeyId
		end

	insert mem.kvValues ([KeyId], Part) select @KeyId, Part from @Values order by [SortOrder]
end